/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						 sound_cache.cpp

	$Header: /heroes4/sound_cache.cpp $

	$NoKeywords: $

 ************************************************************************/

#include "precompiled.h"
#include "sound_cache.h"

#include <streambuf>

#include "abstract_resource_cache.h"
#include "abstract_resource_file.h"
#include "sized_int_types.h"
#include "sound.h"
#include "sound_stream.h"
#include "streambuf_operators.h"
#include "streambuf_ptr.h"
#include "wave_stream.h"
#include "resource_dir.h"


namespace
{
	const int k_wave_buffer_size_limit = 1024*100;

	// -----------------------------------------------------------------
	// wave stream
	// -----------------------------------------------------------------
	class t_wave_disk_stream : public t_sound_stream
	{
	public:
		t_wave_disk_stream( t_streambuf_ptr stream );
		virtual int read( void* data, t_uint32 size );
 	protected:
		t_streambuf_ptr m_stream;
	};

	// -----------------------------------------------------------------
	// wave object
	// -----------------------------------------------------------------
	class t_wave : public t_abstract_sound
	{
	public:
		t_wave( t_abstract_resource_file_ptr resource, int offset );

		virtual char const*         get_extension() const;
		virtual t_sound_stream_ptr  get_stream() const;
		virtual bool				is_mp3() const;
		virtual bool                read( std::streambuf& stream );
	protected:
		t_abstract_resource_file_ptr m_resource;
		t_shared_array<char>         m_data;
		int                          m_offset;
	};

	// -----------------------------------------------------------------
	// cache for sound object
	// -----------------------------------------------------------------
	class t_sound_cache_data : public t_abstract_resource_cache_data<t_sound>
	{
	public:
		t_sound_cache_data( std::string const& name )
			: t_abstract_resource_cache_data<t_sound>( name )
		{
		}
	protected:
		virtual char const* get_prefix() const;
		virtual t_sound*	do_read( std::streambuf & stream, t_progress_handler* handler );
	};

};
 
// -----------------------------------------------------------------
// wave stream
// -----------------------------------------------------------------
t_wave_disk_stream::t_wave_disk_stream( t_streambuf_ptr stream ) : m_stream( stream )
{
}

// -----------------------------------------------------------------
// wave stream
// -----------------------------------------------------------------
int t_wave_disk_stream::read( void* data, t_uint32 size )
{
	return ::read( *m_stream, data, size );
}

// -----------------------------------------------------------------
// wave object
// -----------------------------------------------------------------
t_wave::t_wave( t_abstract_resource_file_ptr resource, int offset ) : m_resource( resource )
{
	m_offset = offset;
}

// -----------------------------------------------------------------
// wave object
// -----------------------------------------------------------------
char const* t_wave::get_extension() const
{
	return "wav";
}

// -----------------------------------------------------------------
// wave object
// -----------------------------------------------------------------
t_sound_stream_ptr  t_wave::get_stream() const
{
	if (m_data != 0)
		return new t_wave_stream( m_data, m_size );

	t_streambuf_ptr stream = m_resource->get_stream(m_offset);
	t_sound_header  header;

	// discard type
	get<t_uint8>( *stream );
	header.read( *stream );
	return new t_wave_disk_stream( stream );
}

// -----------------------------------------------------------------
// wave object
// -----------------------------------------------------------------
bool t_wave::is_mp3() const
{
	return false;
}

// -----------------------------------------------------------------
// wave object
// -----------------------------------------------------------------
bool t_wave::read( std::streambuf& stream )
{
	if (!t_abstract_sound::read( stream ))
		return false;

	if (m_size < k_wave_buffer_size_limit)
	{
		m_data = new char[m_size];
		::read( stream, m_data.get(), m_size );
	}
	return true;
};

// -----------------------------------------------------------------
// cache for sound object
// -----------------------------------------------------------------
char const * t_sound_cache_data::get_prefix() const
{
	return t_resource_traits<t_sound>::prefix;
}

// -----------------------------------------------------------------
// cache for sound object
// -----------------------------------------------------------------
t_sound* t_sound_cache_data::do_read( std::streambuf & stream, t_progress_handler* )
{
	bool is_mp3;

	is_mp3 = get<t_uint8>( stream ) != 0;
	if (is_mp3)
	{
		//== writen by sunjun ==//
		/*
		t_resource_entry const* entry = ::find_resource( "sound.miscellaneous.button.h4d" );		
		if (entry == 0) return 0;
		t_streambuf_ptr stream_ptr = entry->file->get_stream( entry->offset );
		if (stream_ptr == 0) return 0;
		is_mp3 = get<t_uint8>( *stream_ptr ) != 0;
		t_counted_ptr<t_wave> sound = new t_wave( entry->file, entry->offset );
		if (!sound->read( *stream_ptr )) return 0;
		*/
		return new t_sound( 0 );	
	}

	t_counted_ptr<t_wave> sound = new t_wave( m_file, m_offset );

	if (!sound->read( stream ))
		return 0;
	return new t_sound( sound );
}

// -----------------------------------------------------------------
// cache for sound object
// -----------------------------------------------------------------
t_sound_cache::t_sound_cache( std::string const & name )
             : t_abstract_cache<t_sound>( new t_sound_cache_data( name ))
{
}
